﻿namespace EFS.RC.ClientPlatform
{
	/// <summary>
	/// End point
	/// </summary>
	public class EndPoint : EFS.Common.Async.AsyncRoot
	{
		#region Locals

		// sync access
		private static object syncAccess = new object();

		// End Point
		private Microsoft.Rtc.Collaboration.UserEndpoint collaborationApplicationEndpoint;

		/// <summary>
		/// Status
		/// </summary>
		public enum EndPointStatus { Idle, Started, Terminated }

		// Status
		private EndPointStatus status = EndPointStatus.Idle;

		#endregion // Locals

		#region Delgates

		/// <summary>
		/// Shut down event delegate
		/// </summary>
		public delegate void Terminated();

		/// <summary>
		/// Terminated session delegate registrar
		/// </summary>
		public Terminated OnTerminated = null;

		/// <summary>
		/// Shut down event delegate
		/// </summary>
		public delegate void Established();

		/// <summary>
		/// Established session delegate registrar
		/// </summary>
		public Established OnEstablished = null;

		#endregion

		#region Constructor

		/// <summary>
		/// Private constructor
		/// </summary>
		internal EndPoint() { }

		#endregion

		#region Usage

		/// <summary>
		/// Describe this object
		/// </summary>
		/// <returns></returns>
		public override System.String Describe()
		{
			return "EFS.RC.C.EndPoint";
		}

		/// Get status
		public EndPointStatus Status
		{
			get { return status; }
		}

		/// <summary>
		/// Begin startup
		/// </summary>
		internal EFS.Common.Async.AsyncProcess BeginStartup()
		{
			// log
			EFS.EventLog.Log.LogInfo("BeginStartup", this);

			// start-up
			return BeginAsyncProcess2(Startup, OnStartupComplete);
		}

		/// <summary>
		/// Begin shutdown
		/// </summary>
		internal EFS.Common.Async.AsyncProcess BeginShutdown()
		{
			// log
			EFS.EventLog.Log.LogInfo("BeginShutdown", this);

			// shutdown
			return BeginAsyncProcess2(Shutdown, OnShutdownComplete);
		}

		/// <summary>
		/// Make conversation
		/// </summary>
		/// <returns></returns>
		internal Microsoft.Rtc.Collaboration.Conversation MakeConversation()
		{
			// check if we have an application
			EFS.Common.Verify.Reference(collaborationApplicationEndpoint, "Collaboration Application EndPoint not Created for this Application End Point");

			// make remote presence view
			return new Microsoft.Rtc.Collaboration.Conversation(collaborationApplicationEndpoint);
		}

		#endregion

		#region Startup

		/// <summary>
		/// EndPoint startup
		/// </summary>
		private void Startup()
		{
			// log
			EFS.EventLog.Log.LogInfo("Startup", this);

			// lock access
			lock (syncAccess)
			{
				if (status != EndPointStatus.Idle)
				{
					throw new System.InvalidOperationException("Only Idle EndPoint can be started");
				}

				// started
				status = EndPointStatus.Started;
			}

			// make settings
			Microsoft.Rtc.Collaboration.UserEndpointSettings userEndpointSettings =
				new Microsoft.Rtc.Collaboration.UserEndpointSettings(
					EFS.AD.Current.User.SIP,
					EFS.RC.ClientPlatform.Settings.LynkServerFqdn);

			// create credentials
			userEndpointSettings.Credential = System.Net.CredentialCache.DefaultNetworkCredentials;
		
			// instance end point
			collaborationApplicationEndpoint = new Microsoft.Rtc.Collaboration.UserEndpoint(EFS.RC.ClientPlatform.Platform.Instance.CollaborationPlatform, userEndpointSettings);

			// setablish
			collaborationApplicationEndpoint.BeginEstablish(OnEndPointEstablishComplete, null);		
		}

		/// <summary>
		/// Start-up complete
		/// </summary>
		/// <param name="ar"></param>
		private void OnStartupComplete(EFS.Common.Async.AsyncProcess ap)
		{
			// log
			EFS.EventLog.Log.LogInfo("OnStartupComplete", this);

			try
			{
				// check
				ap.Throw();
			}
			catch (System.Exception ex)
			{
				// log
				EFS.EventLog.Log.LogException(ex, this);

				// shutdown
				BeginShutdown();
			}
		}

		/// <summary>
		/// Complete establish
		/// </summary>
		/// <param name="ar"></param>
		private void OnEndPointEstablishComplete(System.IAsyncResult ar)
		{
			// log
			EFS.EventLog.Log.LogInfo("OnEndPointEstablishComplete", this);

			try
			{
				// end
				collaborationApplicationEndpoint.EndEstablish(ar);

				// check delegate
				if (null != OnEstablished)
				{
					// call
					OnEstablished();
				}
			}
			catch (System.Exception ex)
			{
				EFS.EventLog.Log.LogException(ex, this);

				// shut down
				BeginShutdown();
			}
		}

		#endregion // Startup

		#region Runtime

		/// <summary>
		/// Unhandled exception
		/// </summary>
		/// <param name="ex"></param>
		protected override void OnException(System.Exception ex)
		{
			// check
			EFS.Common.Verify.Reference(ex, "ex");

			// log
			EFS.EventLog.Log.LogException(ex, this);

			// close
			BeginShutdown();
		}

		#endregion

		#region Shutdown

		/// <summary>
		/// Shutdown
		/// </summary>
		private void Shutdown()
		{
			// log
			EFS.EventLog.Log.LogInfo("Shutdown", this);

			// lock local acess
			lock (syncAccess)
			{
				// check already terminated
				if (status != EndPointStatus.Terminated)
				{
					// set terinated
					status = EndPointStatus.Terminated;
				}
				else
				{
					// already terminated
					return;
				}
			}

			// check
			if (null != collaborationApplicationEndpoint &&
				collaborationApplicationEndpoint.State != Microsoft.Rtc.Collaboration.LocalEndpointState.Terminated)
			{
				// terminate app
				collaborationApplicationEndpoint.BeginTerminate(EndPointTerminateComplete , collaborationApplicationEndpoint);
			}
		}

		/// <summary>
		/// Shut down complete
		/// </summary>
		/// <param name="ap"></param>
		private void OnShutdownComplete(EFS.Common.Async.AsyncProcess ap)
		{
			// log
			EFS.EventLog.Log.LogInfo("OnShutdownComplete", this);

			try
			{
 				// check delegate
				if (null != OnTerminated)
				{
					// call
					OnTerminated();
				}
			}
			catch (System.Exception ex)
			{
				// log
				EFS.EventLog.Log.LogException(ex, this);
			}
		}

		/// <summary>
		/// Terminate complete
		/// </summary>
		/// <param name="ar"></param>
		void EndPointTerminateComplete (System.IAsyncResult ar)
		{
			// log
			EFS.EventLog.Log.LogInfo("EndPointTerminateComplete", this);

			try
			{
				// make sure all ok
				(ar.AsyncState as Microsoft.Rtc.Collaboration.UserEndpoint).EndTerminate(ar);

				// log
				EFS.EventLog.Log.LogInfo("EndPointTerminateComplete SUCCCESS", this);
			}
			catch (System.Exception ex)
			{
				// log
				EFS.EventLog.Log.LogException(ex, this);
			}
		}

		#endregion // Shutdown
	}
}
